package crypto

import (
	"crypto/aes"
	"crypto/cipher"
	"strings"
	"encoding/hex"
	"encoding/base64"
	"errors"
	"bytes"
	"crypto/des"
	"crypto/md5"
	"net/url"
	"crypto/sha1"
	"crypto/hmac"
	"crypto/sha256"
	"crypto/sha512"
)
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padget := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padget...)
}
//CBC的方式加密转换成
//plaintext 加密文本
//key 加密密钥 iv 加密向量 outputtype 输出格式 默认两种ges hex与base64
func AesEncrypt(plaintext, key, iv, outputtype string) (string, error) {
	block, err := aes.NewCipher([]byte(key))
	if err != nil {
		return "", errors.New("invalid decrypt key")
	}
	blockSize := block.BlockSize()
	var plaintextByte = PKCS7Padding([]byte(plaintext), blockSize)
	blockMode := cipher.NewCBCEncrypter(block, []byte(iv))
	ciphered := make([]byte, len(plaintextByte))
	blockMode.CryptBlocks(ciphered, plaintextByte)
	if strings.EqualFold(strings.ToLower(outputtype),"hex"){
		return hex.EncodeToString(ciphered), nil
	}else {
		return base64.StdEncoding.EncodeToString(ciphered),nil
	}

}


//region base64
func UnBase64(source string) ([]byte, error) {
	return base64.StdEncoding.DecodeString(source)
}

//转base64
func Base64(src []byte) string {
	return base64.StdEncoding.EncodeToString(src)
}
//endregion

//region url

func UrlEncode(source string) string {
	return url.QueryEscape(source)
}

func UrlDecode(source string) (string, error) {
	return url.QueryUnescape(source)
}

//endregion

//region sha

func Sha1(message []byte) string {
	h := sha1.New()
	h.Write(message)
	return hex.EncodeToString(h.Sum(nil))
}

func HmacSha1(message, secret []byte) []byte { //secret 密钥 40位
	h := hmac.New(sha1.New, secret)
	h.Write(message)
	return h.Sum(nil)
}
func HmacSha256(message, secret []byte) []byte { //64位
	h := hmac.New(sha256.New, secret)
	h.Write(message)
	return h.Sum(nil)
}

func HmacSha512(message, secret []byte) []byte { //128位
	h := hmac.New(sha512.New, secret)
	h.Write(message)
	return h.Sum(nil)
}

//endregion
//MD5加密 返回16进制数据 不可逆
func Md5(s string) string {
	h := md5.New()
	h.Write([]byte(s))
	return hex.EncodeToString(h.Sum(nil))
}
//带密钥的加密
func HmacMd5(message, secret []byte) []byte {
	h := hmac.New(md5.New, secret)
	h.Write(message)
	return h.Sum(nil)
}
//DES 目前向量或密钥固定在8字节
func DesEncrypt(origData, key, iv,outputtype string) (string, error) {
	block, err := des.NewCipher([]byte(key))
	if err != nil {
		return "", err
	}
	var plaintextByte = PKCS7Padding([]byte(origData), block.BlockSize())
	blockMode := cipher.NewCBCEncrypter(block, []byte(iv))
	ciphered := make([]byte, len(plaintextByte))
	blockMode.CryptBlocks(ciphered, plaintextByte)

	if strings.EqualFold(strings.ToLower(outputtype),"hex"){
		return hex.EncodeToString(ciphered), nil
	}else {
		return base64.StdEncoding.EncodeToString(ciphered),nil
	}
}